gl renderer: Implement simple shadow nodes
authorTimm Bäder <mail@baedert.org>
Fri, 1 Dec 2017 09:27:31 +0000 (10:27 +0100)
committerTimm Bäder <mail@baedert.org>
Thu, 21 Dec 2017 18:12:31 +0000 (19:12 +0100)
gsk/gl/gskglrenderer.c
gsk/gl/gskglrenderopsprivate.h
gsk/meson.build
gsk/resources/glsl/shadow.fs.glsl [new file with mode: 0644]

index d421734e32d270d99f256c590c6822eb9ba6be83..d3c59fc65a2f73aa34307f41855c12ae80d9a16a 100644 (file)
@@ -171,6 +171,7 @@ struct _GskGLRenderer
       Program blur_program;
       Program inset_shadow_program;
       Program outset_shadow_program;
+      Program shadow_program;
     };
   };
 
@@ -321,6 +322,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
       { "blur",            "blit.vs.glsl",  "blur.fs.glsl" },
       { "inset shadow",    "blit.vs.glsl",  "inset_shadow.fs.glsl" },
       { "outset shadow",   "blit.vs.glsl",  "outset_shadow.fs.glsl" },
+      { "shadow",          "blit.vs.glsl",  "shadow.fs.glsl" },
   };
 
   builder = gsk_shader_builder_new ();
@@ -431,6 +433,9 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
   INIT_PROGRAM_UNIFORM_LOCATION2 (outset_shadow, corner_widths);
   INIT_PROGRAM_UNIFORM_LOCATION2 (outset_shadow, corner_heights);
 
+  /* shadow */
+  INIT_PROGRAM_UNIFORM_LOCATION2 (shadow, color);
+
   g_object_unref (builder);
   return TRUE;
 }
@@ -664,7 +669,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
   float max_y = min_y + node->bounds.size.height;
 
   /* Default vertex data */
-  GskQuadVertex vertex_data[GL_N_VERTICES] = {
+  const GskQuadVertex vertex_data[GL_N_VERTICES] = {
     { { min_x, min_y }, { 0, 0 }, },
     { { min_x, max_y }, { 0, 1 }, },
     { { max_x, min_y }, { 1, 0 }, },
@@ -967,6 +972,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
 
       }
     break;
+
     case GSK_COLOR_MATRIX_NODE:
       {
         int texture_id;
@@ -1100,10 +1106,70 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
       }
     break;
 
-do_default:
+    case GSK_SHADOW_NODE:
+      {
+        GskRenderNode *child = gsk_shadow_node_get_child (node);
+        gsize n_shadows = gsk_shadow_node_get_n_shadows (node);
+        guint i;
+
+        /* TODO: shadow nodes are most commonly used for text and icon shadows.
+         *       In both cases, we can avoit the RTT case!
+         *       if the child is neither a text node nor a texture node though, we need
+         *       to fall back to rendering it to a texture and then applying the shadow on that one.*/
+
+        for (i = 0; i < n_shadows; i ++)
+          {
+            const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i);
+            int texture_id;
+            gboolean is_offscreen;
+            graphene_matrix_t offset_matrix;
+            graphene_matrix_t prev_modelview;
+
+            /* TODO: Implement blurred shadow nodes */;
+            if (shadow->radius > 0)
+              {
+                /* TODO: This draws the entire node, not just one shadow. */
+                render_fallback_node (self, node, builder, vertex_data);
+                continue;
+              }
+
+            add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y, child, &texture_id, &is_offscreen);
+
+            ops_set_program (builder, &self->shadow_program);
+            ops_set_color (builder, &shadow->color);
+            ops_set_texture (builder, texture_id);
+
+            offset_matrix = builder->current_modelview;
+            graphene_matrix_translate (&offset_matrix, &GRAPHENE_POINT3D_INIT (shadow->dx, shadow->dy, 0));
+            prev_modelview = ops_set_modelview (builder, &offset_matrix);
+
+            if (is_offscreen)
+              {
+                GskQuadVertex vertex_data[GL_N_VERTICES] = {
+                  { { min_x, min_y }, { 0, 1 }, },
+                  { { min_x, max_y }, { 0, 0 }, },
+                  { { max_x, min_y }, { 1, 1 }, },
+
+                  { { max_x, max_y }, { 1, 0 }, },
+                  { { min_x, max_y }, { 0, 0 }, },
+                  { { max_x, min_y }, { 1, 1 }, },
+                };
+                ops_draw (builder, vertex_data);
+              }
+            else
+              {
+                ops_draw (builder, vertex_data);
+              }
+
+            ops_set_modelview (builder, &prev_modelview);
+          }
+
+        /* Now draw the child normally */
+        gsk_gl_renderer_add_render_ops (self, child, builder);
+      }
+    break;
 
     case GSK_REPEATING_LINEAR_GRADIENT_NODE:
-    case GSK_SHADOW_NODE:
     case GSK_BORDER_NODE:
     case GSK_CROSS_FADE_NODE:
     case GSK_BLEND_NODE:
@@ -1307,7 +1373,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
 
         case OP_CHANGE_COLOR:
           OP_PRINT (" -> Color: (%f, %f, %f, %f)", op->color.red, op->color.green, op->color.blue, op->color.alpha);
-          g_assert (program == &self->color_program || program == &self->coloring_program);
+          g_assert (program == &self->color_program || program == &self->coloring_program ||
+                    program == &self->shadow_program);
+          /* TODO: We use color.color_location here and this is right for all three of the programs above,
+           *       but that's just a coincidence. */
           glUniform4f (program->color.color_location,
                        op->color.red, op->color.green, op->color.blue, op->color.alpha);
           break;
index ec9bc944f678c4820c222e05e67d63c599ff4404..f577bd7e3ad5f9f21c6dbae63e7d011958bae342 100644 (file)
@@ -10,7 +10,7 @@
 #include "gskglrendererprivate.h"
 
 #define GL_N_VERTICES 6
-#define GL_N_PROGRAMS 9
+#define GL_N_PROGRAMS 10
 
 enum {
   OP_NONE,
@@ -59,6 +59,9 @@ typedef struct
     struct {
       int color_location;
     } coloring;
+    struct {
+      int color_location;
+    } shadow;
     struct {
       int color_matrix_location;
       int color_offset_location;
@@ -146,6 +149,9 @@ typedef struct
       float offset[2];
       float color[4];
     } outset_shadow;
+    struct {
+      float color[4];
+    } shadow;
   };
 } RenderOp;
 
index f05cb343e0e949d64caef00e9eb62a715d96b75d..54828e7aa8cdcaaff0fb00f88112ccc133b50b9c 100644 (file)
@@ -11,6 +11,7 @@ gsk_private_source_shaders = [
   'resources/glsl/blur.fs.glsl',
   'resources/glsl/inset_shadow.fs.glsl',
   'resources/glsl/outset_shadow.fs.glsl',
+  'resources/glsl/shadow.fs.glsl',
   'resources/glsl/es2_common.fs.glsl',
   'resources/glsl/es2_common.vs.glsl',
   'resources/glsl/gl3_common.fs.glsl',
diff --git a/gsk/resources/glsl/shadow.fs.glsl b/gsk/resources/glsl/shadow.fs.glsl
new file mode 100644 (file)
index 0000000..3426ba3
--- /dev/null
@@ -0,0 +1,13 @@
+uniform vec4 u_color;
+
+void main() {
+  vec4 diffuse = Texture(u_source, vUv);
+  vec4 color = u_color;
+
+  // pre-multiply
+  color.rgb *= color.a;
+
+  color = vec4(u_color.rgb * diffuse.a, diffuse.a);
+
+  setOutputColor(color);
+}